import timber.ui.GridViewContent;
import timber.ui.GridViewCell;

/**
	Base class for GridView object.
	This will work fine on its own, however you can get more custom behavior by subclassing and defining the
	willRenderRows and didRenderRows methods.


	@author Chandler McWilliams
	@version 2006-11-29
*/
class timber.ui.GridView extends MovieClip
{
	
	private var clip:MovieClip;
	private var content:GridViewContent;
	private var gridCellClip:MovieClip;
	
	private var gridCellClass:Function;
	
	private var gridWidth:Number				= 320;
	private var gridHeight:Number				= 320;

	private var gridCellWidth:Number			= 100;
	private var gridCellHeight:Number		= 100;

	private var maxNumberOfRows:Number		= 3;
	private var maxNumberOfColumns:Number	= 3;
	
	private var cellOffset:Number;
	
	private var cells:Array;

// ===========================================================
// - CONSTRUCTOR
// ===========================================================
	public function GridView(aClip:MovieClip, aDS:Object, aCell:Function) {
		clip = aClip;
		gridCellClass = aCell;
		
		setContent(aDS);
						
		cells = [];
		cellOffset = 0;
		
		// try to devine width and height if possible
		if (clip._width) gridWidth = clip._width;
		if (clip._height) gridHeight = clip._height;
		
		// if there is no gridCells clip, make one
		if (!(gridCellClip instanceof MovieClip)) gridCellClip = clip.createEmptyMovieClip('gridCellClip',0);
		
		render();
	}

// ===========================================================
// - ACCESSORS
// ===========================================================
	public function getContent() { return content; }
	public function setContent(aDS:Object) {
		// convert to GridViewContent if necessary
		content = (!(aDS instanceof GridViewContent))?new GridViewContent(aDS):aDS;
	}
	
	public function getGridCellHeight():Number {	return gridCellHeight; }
	public function setGridCellHeight(aValue:Number) { gridCellHeight = aValue; }

	public function getGridCellWidth():Number { return gridCellWidth; }
	public function setGridCellWidth(aValue:Number) { gridCellWidth = aValue; }
	
	public function getMaxNumberOfRows():Number { return maxNumberOfRows; }
	public function setMaxNumberOfRows(aValue:Number) { maxNumberOfRows = aValue;	}
	
	public function getMaxNumberOfColumns():Number { return maxNumberOfColumns; }
	public function setMaxNumberOfColumns(aValue:Number) { maxNumberOfColumns = aValue;	}

	public function getNumberOfDrawnCells():Number { return cells.length; }
	
	public function getWidth():Number {	return gridWidth; }
	public function setWidth(aValue:Number) {	gridWidth = aValue; }

	public function getHeight():Number {	return gridHeight; }
	public function setHeight(aValue:Number) {	gridHeight = aValue; }
	
	public function getGridCellClip(Void):MovieClip { return gridCellClip; }

	public function getGridCellClass() { return gridCellClass; }
	public function setGridCellClass(val:Function) { gridCellClass = val; }

	public function get offset() { return getOffset(); }
	public function set offset(val:Number) { setOffset(val); }
	public function getOffset() { return cellOffset; }
	public function setOffset(val:Number) { 
		if (val < 0) {
			cellOffset = 0;
		} else if (val > content.length-1) {
			cellOffset = content.length-1;
		} else {
			cellOffset = val;
		} 
	}

// ===========================================================
// - RENDER ALL CELLS IN THE GRID
// ===========================================================
	public function render() {

		// clear the old cells
		reset();
		
		// signal that the cells are about to be drawn
		willRenderCells();
				
		// loop through items in datasource
		var ok:Boolean;
		var c:Number = 0;
		for (var i=cellOffset; i<content.length; i++, c++) {
			ok = renderCellWithData(c, content.objectForCell(i));
			if (!ok) break;
		}
		
		didRenderCells();
	}

	private function renderCellWithData(i:Number, data:Object):Boolean {
		if (getRowForCell(i) >= maxNumberOfRows) return false;
		var cell = new gridCellClass(this, i, data);
		var pos = getPositionForCell(i);
		cell.x = pos.x;
		cell.y = pos.y;
		cell.width = gridCellWidth;
		cell.height = gridCellHeight;			
		cells[i] = cell;
		
		return true;
	}

// ===========================================================
// - CALCULATE CELL POSITIONS
// ===========================================================
	private function getPositionForCell(i:Number):Object {
		var out = {};
		var xpad = (gridWidth - (maxNumberOfColumns*gridCellWidth))/(maxNumberOfColumns+1);
		var ypad = (gridHeight - (maxNumberOfRows*gridCellHeight))/(maxNumberOfRows+1);
		
		out.x = xpad+getColumnForCell(i)*(gridCellWidth + xpad);
		out.y = ypad+getRowForCell(i)*(gridCellHeight + ypad);
		return out;
	}

	public function getColumnForCell(i:Number):Number { return i%maxNumberOfColumns;	}
	public function getRowForCell(i:Number):Number { return Math.floor(i/maxNumberOfColumns);	}

// ===========================================================
// - MISC
// ===========================================================
	public function reset() {
		for (var i=0; i<cells.length; i++) {
			cells[i].destroy();
		}
	}

// ===========================================================
// - TO BE OVERLOADED IN SUBCLASSES
// ===========================================================
	public function willRenderCells() {}
	public function didRenderCells() {}

}